﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using RayDen.Library.Components.Surface;
using RayDen.RayEngine.Core.Types;

namespace RayDen.MegaRay.Core
{
    public class LightPath : IEnumerable<PathVertexData>
    {
        public PathVertex EyeVertex, LightVertex;

        public Sample PathSample;

        public bool PathFinished { get; protected set; }

        public string Expression
        {
            get { return vertices.Select(GetVertexExpression).Aggregate((a, b) => a + b); }
        }

        private readonly LinkedList<PathVertex> vertices;

        public LightPath()
        {
            vertices = new LinkedList<PathVertex>();
        }

        public void StartFromLight(PathVertex lightPath)
        {
            vertices.AddFirst(lightPath);
            this.LightVertex = lightPath;
            this.EyeVertex = null;
            this.PathFinished = false;
        }

        public void StartFromEye(PathVertex eyeVertex)
        {
            vertices.AddLast(eyeVertex);
            EyeVertex = eyeVertex;
            this.LightVertex = null;
            this.PathFinished = false;
        }

        public void AddVertex(PathVertex v)
        {
            if (v.IsCamera() && EyeVertex == null)
            {
                EyeVertex = v;
                vertices.AddLast(v);
                this.PathFinished = true;
            }
            else if (v.IsLight() && LightVertex == null)
            {
                LightVertex = v;
                vertices.AddFirst(v);
                this.PathFinished = true;
            }
            else if (!PathFinished)
            {
                this.vertices.AddLast(v);
            }
        }

        private string GetVertexExpression(PathVertex vertex)
        {

            switch ((PathVertexType)vertex.VertexData.Flags)
            {
                case PathVertexType.Environment:
                    return "A";
                case PathVertexType.Surface:
                    if (vertex.VertexData.Brdf.Type == BrdfType.Diffuse)
                        return "D";
                    if (vertex.VertexData.Brdf.Type == BrdfType.Specular || vertex.VertexData.Brdf.Type == BrdfType.Refractive)
                        return "S";
                    break;
                case PathVertexType.Light:
                    return "L";
                case PathVertexType.Camera:
                    return "E";

            }
            return string.Empty;
        }

        public IEnumerator<PathVertexData> GetEnumerator()
        {
            return vertices.Select(item => item.VertexData).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}